#ifndef __LIBC_X86_XCHG_H
#define __LIBC_X86_XCHG_H

#ifdef __cplusplus
extern "C"
{
#endif

#include <types.h>

    static uint8_t mem_xchg8(uint8_t *ptr, uint8_t val)
    {
        __asm__ __volatile__("xchgb %1,(%0)" ::"a"(ptr), "b"(val)
                             : "memory");
        return val;
    }

    static uint16_t mem_xchg16(uint16_t *ptr, uint16_t val)
    {
        __asm__ __volatile__("xchgw %1,(%0)" ::"a"(ptr), "b"(val)
                             : "memory");
        return val;
    }

    static uint32_t mem_xchg32(uint32_t *ptr, uint32_t val)
    {
        __asm__ __volatile__("xchgl %1,(%0)" ::"a"(ptr), "b"(val)
                             : "memory");
        return val;
    }

    static inline uint32_t mem_xchg(uint32_t x, volatile void *ptr, int size)
    {
        int old;
        switch (size)
        {
        case 1:
            old = mem_xchg8((uint8_t *)ptr, x);
            break;
        case 2:
            old = mem_xchg16((uint16_t *)ptr, x);
            break;
        case 3:
            old = mem_xchg32((uint32_t *)ptr, x);
            break;
        default:
            break;
        }
        return old;
    }

#define xchg(ptr, v) ((__typeof__(*(ptr)))mem_xchg((uint32_t)(v), (ptr), sizeof(*(ptr))))

#define __test_and_set(v, new) (xchg((v), new))

#ifdef __cplusplus
}
#endif
#endif